前幾天我們已經分別看過首頁、查詢結果和詳細頁,也知道各個 ViewModel 大概在做什麼。
但如果現在問我:「使用者從首頁開始查一間空教室,到最後看到這間教室的詳細資料,中間到底發生了什麼?」
我以前其實沒辦法一次講完整。每個檔案我好像都看過,但它們還是分開的;所以今天,我想先不看新的功能,而是把前面讀過的程式重新串一次。
目前為止,我們討論了以下這幾個檔案:
AndroidManifest.xml:指定 App 啟動入口。MainActivity.kt:首頁,讓使用者選大樓。QueryResultActivity.kt:查詢頁 UI 控制器。QueryResultViewModel.kt:查詢條件與空教室篩選核心。EmptyRoomAdapter.kt:把 emptyRooms 顯示成 RecyclerView 列表。RoomDetailActivity.kt:教室詳細頁 UI 控制器。RoomDetailViewModel.kt:根據教室名稱取得詳細資料。Day 10 的目標是從「分開看懂每個檔案」進一步變成「能說出它們如何合作」,這也是為什麼我會特別拉出一個主題來說明。
App 的開啟入口是 AndroidManifest.xml 這個設定檔,但進入的第一個畫面是 MainActivity。
流程是:使用者點 App 圖示 → Android 讀 Manifest → 找到 MAIN + LAUNCHER → 啟動 MainActivity。
MainActivity.kt 處理首頁 UI 互動邏輯,讓使用者選擇大樓,並透過 Intent 把大樓名稱傳給 QueryResultActivity。
流程是:首頁選大樓 → 按查詢 → Intent 帶著 building → 前往 QueryResultActivity。
QueryResultActivity.kt 是查詢頁 UI 控制器。
接收首頁傳來的大樓條件,設定星期、時段、樓層三個 Spinner,並在使用者改變選項時,把目前選到的值寫進 QueryResultViewModel。同時觀察 emptyRooms,讓 Adapter 更新 RecyclerView。
QueryResultViewModel .kt 是從 SavedStateHandle 取得 building,接收 QueryResultActivity 選的日期、時段、樓層。
當條件都準備好後,update() 會把中文大樓轉成 SF/ES,把星期與節次轉成 mon1 等欄位代碼,然後篩選所有教室。只有大樓符合、樓層符合,而且該時段欄位不是 X 的教室,才放進 emptyRooms。
EmptyRoomAdapter.kt 接收 QueryResultViewModel 已經篩選好的 emptyRooms,依教室名稱提取樓層、分組、排序,整理成包含樓層標題與教室項目的 items。
RecyclerView 根據每一列型別建立對應 ViewHolder。點擊教室項目時,Adapter 透過 callback 把該教室資料傳回 QueryResultActivity。
RoomDetailActivity.kt 是詳細頁 UI 控制器。
如果沒有取得教室名稱,就關閉頁面。取得教室名稱後,呼叫 viewModel.getDetails(name) 並觀察回傳資料。
查到 ClassroomSchedule 後,updateUi() 顯示教室名稱,將 classroomType(教室類型)轉成中文,並依是否為 Normal(一般教室) 判斷能否飲食。
RoomDetailViewModel.kt 是教室詳細頁的邏輯中心。
根據 classroomName 透過 Repository 取得該教室的 ClassroomSchedule,用 asLiveData() 將 Repository 回傳的資料流轉成 LiveData<ClassroomSchedule?>,讓 RoomDetailActivity 可以 observe。
AndroidManifest.xml
↓
設定 App 入口
↓
MainActivity
↓
傳遞選擇的大樓 building
↓
QueryResultActivity
↓
取得/記錄查詢條件
星期/時段/樓層
↓
QueryResultViewModel
↓
依大樓、樓層、時段篩選 ClassroomSchedule
↓
取得空教室 emptyRooms
↓
Activity 觀察結果並整理列表
↓
EmptyRoomAdapter / RecyclerView
↓
使用者點選教室
↓
傳遞 classroomName
↓
RoomDetailActivity
↓
查詢該教室詳細資料
↓
RoomDetailViewModel
↓
Repository → LiveData
↓
RoomDetailActivity
↓
顯示教室名稱、教室類型、是否可飲食
AndroidManifest.xml 中的 MAIN + LAUNCHER 啟動 MainActivity。building 傳到 QueryResultActivity。QueryResultViewModel。emptyRooms。EmptyRoomAdapter,Adapter 依樓層整理列表並顯示到 RecyclerView。QueryResultActivity 再用 Intent 把教室名稱傳給 RoomDetailActivity。RoomDetailViewModel 查到該教室資料,最後顯示教室名稱、教室類型與是否可飲食。| 階段 | 檔案 | 負責什麼 | 傳遞 / 產生的資料 |
|---|---|---|---|
| 1 | AndroidManifest.xml |
告訴 Android 啟動入口 | MAIN + LAUNCHER |
| 2 | MainActivity.kt |
首頁選大樓 | building |
| 3 | QueryResultActivity.kt |
查詢頁 UI、收集條件 | building / day / time / floor |
| 4 | QueryResultViewModel.kt |
篩選空教室 | emptyRooms |
| 5 | EmptyRoomAdapter.kt |
顯示空教室列表 | 樓層標題 + 教室項目 |
| 6 | RoomDetailActivity.kt |
顯示教室詳細頁 | classroomName / schedule |
| 7 | RoomDetailViewModel.kt |
查詢單一教室資料 | LiveData |
整理完整使用者查詢流程後,我發現 RoomRush 的功能不是由單一檔案完成,而是由多個檔案各自負責一段
MainActivity 負責收集第一個條件:大樓。QueryResultActivity 負責查詢頁互動。QueryResultViewModel 才是真正把條件轉成空教室列表的地方。EmptyRoomAdapter 則把結果整理成有樓層標題的列表。這次總結讓我更理解 Android 專案的分工:Activity 不應該包辦所有事情,ViewModel 也不負責顯示畫面。每個檔案看起來分散,但如果沿著資料流追,就能看到它們如何一起完成「查詢空教室」這個功能。
使用者查詢流程的第一階段在此圓滿告一段落。下一階段,我們要正式進入到「資料來源主線」。
要計算空教室,我們首先就是要搞懂資料的源頭:**「一間教室的一週課表,在 RoomRush 裡是如何被表示成 Room Entity 與資料表欄位的?」,**這部分是了解資料庫在空教室查詢系統中,很重要的一個環節。